/**
 * 
 */
package com.ray.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ConnectException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import net.sf.json.JsonConfig;

/**
* <p>考勤工具类
* @author 王荣
*/
public class DingTalkUtil{
	private static Logger log = LoggerFactory.getLogger(DingTalkUtil.class);  
	
	public final static String access_token_url = "https://oapi.dingtalk.com/gettoken";
	public final static String CORP_ID = "ding5eca4da483bbcfcc35c2f4657eb6378f";
	public final static String CORP_SECRET = "X_vS83aTrbOHkexLpbb28Hq-fAS364q-sTNJi7ANg0kXQdPXWqX1_4iXWmi_3A9s";
	//获取部门成员url
	public final static String user_simplelist_url= "https://oapi.dingtalk.com/user/simplelist?access_token=ACCESS_TOKEN&department_id=DEPARTMENT_ID";
	//考勤打卡数据url
	public final static String attendance_list_url= "https://oapi.dingtalk.com/attendance/list?access_token=ACCESS_TOKEN";
	//获取部门列表
	public final static String department_list_url = "https://oapi.dingtalk.com/department/list?access_token=ACCESS_TOKEN";
	
	public final static String TIME_RESULT_LEAVE = "leave";
	public final static String TIME_RESULT_NORMAL = "normal";
	public final static String TIME_RESULT_LACK = "lack";
	public final static String TIME_RESULT_LATE = "late";
	public final static String TIME_RESULT_EARLY = "early";
	public final static String TIME_RESULT_REST = "rest";
	
	private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
	
	/**
	 * Title: getDepartmentList
	 * Description: 获取部门列表  
	 * @return  
	 * @author 王荣
	 */
	public static JSONObject getDepartmentList() {
		String accessToken = getAccessToken();
		String url = department_list_url.replace("ACCESS_TOKEN", accessToken);
		//2.发送请求
		JSONObject jsonObject = httpRequest(url,"GET",null);
		//3.错误消息处理
        if (null != jsonObject) {  
            if (0 != jsonObject.getInteger("errcode")) {  
                log.error("获取部门列表失败 errcode:{} errmsg:{}", jsonObject.get("errcode"), jsonObject.getString("errmsg"));  
            }  
        }  
		return jsonObject;
	}
	/**
	 * Title: getDepartmentUser
	 * Description: 获取部门成员  
	 * @return com.alibaba.fastjson.JSONObject
	 * @author 王荣
	 */
	public static JSONObject getDepartmentUser(String accessToken,String deptId) {
		String url = user_simplelist_url.replace("ACCESS_TOKEN", accessToken).replace("DEPARTMENT_ID", deptId);
		System.out.println("getDepartmentUser_URL:"+url);
		//发送请求
		JSONObject jsonObject = httpRequest(url,"GET",null);
		//3.错误消息处理
        if (null != jsonObject) {  
            if (0 != jsonObject.getInteger("errcode")) {  
                log.error("获取部门成员失败 errcode:{} errmsg:{}", jsonObject.get("errcode"), jsonObject.getString("errmsg"));  
            }  
        }  
		return jsonObject;
	}
	/**
     * 1.发起https请求并获取结果 
     * @param requestUrl 请求地址 
     * @param requestMethod 请求方式（GET、POST） 
     * @param outputStr 提交的数据 
     * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) 
     */  
    public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {  
        JSONObject jsonObject = null;  
        StringBuffer buffer = new StringBuffer();  
        try {  
            // 创建SSLContext对象，并使用我们指定的信任管理器初始化  
            TrustManager[] tm = { new MyX509TrustManager() };  
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");  
            sslContext.init(null, tm, new java.security.SecureRandom());  
            // 从上述SSLContext对象中得到SSLSocketFactory对象  
            SSLSocketFactory ssf = sslContext.getSocketFactory();  

            URL url = new URL(requestUrl);  
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();  
            httpUrlConn.setSSLSocketFactory(ssf);  

            httpUrlConn.setDoOutput(true);  
            httpUrlConn.setDoInput(true);  
            httpUrlConn.setUseCaches(false);  
            // 设置请求方式（GET/POST）  
            httpUrlConn.setRequestMethod(requestMethod);  

            if ("GET".equalsIgnoreCase(requestMethod)) {
            	httpUrlConn.connect();  
            }

            // 当有数据需要提交时  
            if (null != outputStr) {  
                OutputStream outputStream = httpUrlConn.getOutputStream();  
                // 注意编码格式，防止中文乱码  
                outputStream.write(outputStr.getBytes("UTF-8"));  
                outputStream.close();  
            }  

            // 将返回的输入流转换成字符串  
            InputStream inputStream = httpUrlConn.getInputStream();  
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");  
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  

            String str = null;  
            while ((str = bufferedReader.readLine()) != null) {  
                buffer.append(str);  
            }  
            bufferedReader.close();  
            inputStreamReader.close();  
            // 释放资源  
            inputStream.close();  
            inputStream = null;  
            httpUrlConn.disconnect();  
            jsonObject = JSONObject.parseObject(buffer.toString());  
        } catch (ConnectException ce) {  
            log.error("DingTalk server connection timed out.");  
        } catch (Exception e) {  
            log.error("https request error:{}", e);  
        }  
        return jsonObject;  
    }  
	
	/**
     * 获取钉钉的accessToken
     */
    public static String getAccessToken(){
        String requestUrl = access_token_url + "?corpid="+CORP_ID+"&corpsecret="+CORP_SECRET;
        String result = doGet(requestUrl);
        String accessToken = null;
        com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
        jsonObject = JSON.parseObject(result);
        String msg = (String)jsonObject.get("errmsg");
        if("ok".equals(msg)){
            accessToken = (String)jsonObject.get("access_token");
        }
        return accessToken;
    }
    //获取打卡信息列表accessToken,workDateFrom,workDateTo,offset,limit
    public static JSONArray getCardList(String accessToken, String workDateFrom, String workDateTo){
        String recordUrl = "https://oapi.dingtalk.com/attendance/list?access_token="+accessToken;
        JSONObject jsonObject = new JSONObject();
        System.out.println("workDateFrom:"+workDateFrom+" AndWorkDateTo:"+workDateTo);
        jsonObject.put("workDateFrom",workDateFrom);
        jsonObject.put("workDateTo",workDateTo);
//        jsonObject.put("offset",offset);
//        jsonObject.put("limit",limit);
        String result = doPost(recordUrl,jsonObject,"utf-8");
        com.alibaba.fastjson.JSONObject resultJSON = com.alibaba.fastjson.JSONObject.parseObject(result);
        String msg = (String)resultJSON.get("errmsg");
        System.out.println("message:"+msg);
        JSONArray jsonArray = null;
        if("ok".equals(msg)){
            jsonArray = (JSONArray) resultJSON.get("recordresult");
        }
        return jsonArray;
    }
	
    public static String doGet(String url){
        String result = null;
        HttpGet request = new HttpGet(url);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            HttpResponse response = httpClient.execute(request);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                result= EntityUtils.toString(response.getEntity(),"utf-8");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }
    public static JSONObject httpGet(String url) throws Exception {
		//1.创建httpClient 
		CloseableHttpClient httpClient = HttpClients.createDefault();
		//2.生成一个请求
		HttpGet httpGet = new HttpGet(url);
		//3.配置请求的属性
		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();
		httpGet.setConfig(requestConfig);
        
		//4.发起请求，获取响应信息
		CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(httpGet, new BasicHttpContext());

			//如果返回结果的code不等于200，说明出错了  
			if (response.getStatusLine().getStatusCode() != 200) {

				System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()
						+ ", url=" + url);
				return null;
			}
			//5.解析请求结果
			HttpEntity entity = response.getEntity();      //reponse返回的数据在entity中 
			if (entity != null) {
				String resultStr = EntityUtils.toString(entity, "utf-8");  //将数据转化为string格式  

				JSONObject result = JSON.parseObject(resultStr);    //将String转换为 JSONObject
				if (result.getInteger("errcode") == 0) {
					return result;
				} else {
					System.out.println("request url=" + url + ",return value=");
					System.out.println(resultStr);
					int errCode = result.getInteger("errcode");
					String errMsg = result.getString("errmsg");
					throw new Exception("error code:"+errCode+", error message:"+errMsg); 
				}
			}
		} catch (IOException e) {
			System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
			e.printStackTrace();
		} finally {
			if (response != null) try {
				response.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return null;
	}
    
    public static String doPost(String url, JSONObject jsonObject, String charset){
    	CloseableHttpClient httpClient = null;
        HttpPost httpPost = null;
        String result = null;
        try{
        	httpClient = HttpClients.createDefault();
            httpPost = new HttpPost(url);
            //设置参数
            StringEntity entity = new StringEntity(jsonObject.toString(),charset);
            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);

            HttpResponse response = httpClient.execute(httpPost);
            if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity resEntity = response.getEntity();
                if(resEntity != null){
                    result = EntityUtils.toString(resEntity,charset);
                }
            }
        }catch(Exception ex){
            ex.printStackTrace();
        }
        return result;
    }
    /**
     * Description: 通过截取list分批插入数据
     * 解决SQLServerException:传入的表格格式数据流远程过程调用协议流不正确。此RPC请求中提供了过多的参数。最多应为2100
     * 目前没有使用
     * @param beanList 
     * @param className Class类的静态路径  例：com.ray.service.AttendanceService
     * @param methodName Class类的方法名
     * @param size list每次截取的size
     * 调用mapper接口时 InstantiationException 不能实例化接口和抽象类
     * 在service中添加方法后，又抛出 java.lang.reflect.InvocationTargetException
     * @author 王荣
     */
    public static <T> void batchInsert(List<T> beanList, String className,String methodName, int size) {
		List<T> childrenList = null;
		Class<?> clazz;
		try {
			clazz = Class.forName(className);
			Method method = clazz.getMethod(methodName, List.class);
	        if(beanList!=null && beanList.size()>0) {
	        	if(beanList.size()>size) {
	        		int count = (int)Math.floor(beanList.size()/size);
	        		for(int i=0;i<count;i++) {
	        			childrenList = beanList.subList(i*size, (i+1)*size);
	        			method.invoke(clazz.newInstance(), childrenList);
	        		}
	        		//防止下标越界
	        		childrenList = beanList.subList(count*size, beanList.size());
	        		method.invoke(clazz.newInstance(), childrenList);
	        	}else {
	        		method.invoke(clazz.newInstance(), beanList);
	        	}
	        }
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
    }
    /**
     * 解析页面传递的数组JSON字符串为list<Map<String,Object>>
     * @param jsonArrStr
     * @return
     * @author 王荣
     */
    public static List<Map<String, Object>> parseJsonArrayStrToList(String jsonArrStr){
    	net.sf.json.JSONArray jsonArray = net.sf.json.JSONArray.fromObject(jsonArrStr);
    	List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		for (int i = 0; i < jsonArray.size(); i++){
			net.sf.json.JSONObject jsonObject = jsonArray.getJSONObject(i);
			Map<String, Object> map = new HashMap<String, Object>();
			for (Iterator<?> iter = jsonObject.keys(); iter.hasNext();){
			    String key = (String) iter.next();
			    Object value = jsonObject.get(key);
			    map.put(key, value);
			}
			list.add(map);
		}
		return list;
    }
    public static List<Integer> parseJsonArrayStrToListInteger(String jsonArrStr){
    	net.sf.json.JSONArray jsonArray = net.sf.json.JSONArray.fromObject(jsonArrStr);
    	@SuppressWarnings({ "unchecked", "static-access" })
		List<Integer> list = jsonArray.toList(jsonArray,Integer.class,new JsonConfig());
		return list;
    }
 // 将jsonArray字符串转换成List集合
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static List jsonStrToList(String jsonStr, Class beanClass) {
		if (!StringUtils.isBlank(jsonStr)) {
			return com.alibaba.fastjson.JSONObject.parseArray(jsonStr, beanClass);
		} else {
			return null;
		}
	}
	//List集合转换为json
	@SuppressWarnings("rawtypes")
	public static JSON listToJson(List list) {
		JSON json=(JSON) com.alibaba.fastjson.JSON.toJSON(list);
		return json;
	}
	/**
	 * 判断日期字符串是星期几
	 * @param dateStr
	 * @return 星期几
	 * @author 王荣
	 */
	public static String getWeekOfDateStr(String dateStr) {
		Date date = null;
		try {
			date = simpleDateFormat.parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int w = cal.get(Calendar.DAY_OF_WEEK)-1;
		return weekDays[w];
	}
	/**
	 * 对象转map
	 * @param obj
	 * @return
	 * @author 王荣
	 */
	public static Map<String, Object> object2Map(Object obj) {
		Map<String, Object> map = new HashMap<String, Object>();
		if (obj == null) {
			return map;
		}
		@SuppressWarnings("rawtypes")
		Class clazz = obj.getClass();
		Field[] fields = clazz.getDeclaredFields();
		try {
			for (Field field : fields) {
				field.setAccessible(true);
				map.put(field.getName(), field.get(obj));
			}
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return map;
	}
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Object Object2Object(Object obj1,Object obj2) {
		ObjectMapper MAPPER = new ObjectMapper();
		String jsonStr;
		Class clazz = obj2.getClass();
		try {
			jsonStr = MAPPER.writeValueAsString(obj1);
			obj2 = MAPPER.readValue(jsonStr , clazz);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return obj2;
	}
	/**
	 * 需审批，以审批单为准计算当天的加班时长
	 * @param currentDayOvertimeList 当天关联的加班审批列表
	 * @param workdate 当天日期
	 * @return 当天的加班时长
	 * @throws NumberFormatException
	 * @throws ParseException
	 * @author 王荣
	 */
	public static long calculateOvertimeDuration(List<Map<String, Object>> currentDayOvertimeList,
											String workdate) throws NumberFormatException, ParseException {
		long workOvertimeRestDayDuration = 0;
		for(Map<String, Object> overtimeApproval : currentDayOvertimeList) {
			String startTime = overtimeApproval.get("startTime").toString();
			String endTime = overtimeApproval.get("endTime").toString();
			if(TimeAndUnix.getDateDays(startTime,endTime)==0) {
				//加班审批不跨天
				double duration = Double.valueOf(overtimeApproval.get("duration").toString());
				workOvertimeRestDayDuration += duration*60*60*1000;
			}else {//跨天
				if(TimeAndUnix.getDateDays(startTime,workdate)==0 
						&& TimeAndUnix.getDateDays(workdate,endTime)>0) {
					//今天加到第二天 只计算审批开始到24点
					workOvertimeRestDayDuration += TimeAndUnix.compareDate(startTime,null ,TimeAndUnix.timeAddDay(startTime,1),"yyyy-MM-dd");
				}else if(TimeAndUnix.getDateDays(startTime,workdate)>0
							&& TimeAndUnix.getDateDays(workdate,endTime)==0) {
					//昨天加班到今天，计算今天00:00到审批结束
					workOvertimeRestDayDuration += TimeAndUnix.compareDate(workdate,"yyyy-MM-dd",endTime,null);
				}else if(TimeAndUnix.getDateDays(startTime,workdate)>0 
						&& TimeAndUnix.getDateDays(workdate,endTime)>0) {
					//加班审批10-01~10-03 workdate：10-02 只计算workdate当天的加班时长24小时
					workOvertimeRestDayDuration += 24*60*60*1000;
				}
			}
		}
		return workOvertimeRestDayDuration;
	}
	/**
	 * 需审批，以打卡为准，但不能超过审批单时长
	 * @param currentDayOvertimeList 当天加班审批列表
	 * @param baseCheckTime 加班开始时间
	 * @param userCheckTime 加班结束时间
	 * @return 当天的加班时长
	 * @author 王荣
	 */
	public static long calculateOvertimeDuration(List<Map<String, Object>> currentDayOvertimeList,
											String baseCheckTime,String userCheckTime) {
		long workOvertimeRestDayDuration = 0;
		for(Map<String, Object> overtimeApproval : currentDayOvertimeList) {
			String startTime = overtimeApproval.get("startTime").toString();
			String endTime = overtimeApproval.get("endTime").toString();
			double duration = Double.valueOf(overtimeApproval.get("duration").toString());
			double start_sCheck = TimeAndUnix.compareDate(baseCheckTime, startTime);
			double end_eCheck = TimeAndUnix.compareDate(userCheckTime,endTime);
			if(start_sCheck>=0 && end_eCheck<=0) {
				//加班审批08:00-11:00 打卡07:55-11:05 打卡范围包含加班审批，直接取加班审批时长
				workOvertimeRestDayDuration += duration*60*60*1000;
			}else if(start_sCheck>=0 && end_eCheck>=0 && TimeAndUnix.compareDate(startTime,userCheckTime)>0) {
				//08:00-11:00加班审批 07:55-10:00打卡 加班审批结束前下班打卡，计算加班时长为加班审批开始-下班打卡
				workOvertimeRestDayDuration += TimeAndUnix.compareDate(startTime,userCheckTime);
			}else if(start_sCheck<=0 && end_eCheck<=0 && TimeAndUnix.compareDate(baseCheckTime,endTime)>=0) {
				//08:00-11:00加班审批 09:00-11:05打卡 加班审批开始后上班打卡，计算加班时长为上班打卡-加班审批结束
				workOvertimeRestDayDuration += TimeAndUnix.compareDate(baseCheckTime,endTime);
			}else if(start_sCheck<=0 && end_eCheck>=0) {
				//08:00-11:00加班审批 09:00-10:00打卡 打卡范围在加班审批范围内，计算加班时长为打卡时长
				workOvertimeRestDayDuration += TimeAndUnix.compareDate(baseCheckTime,userCheckTime);
			}
		}
		return workOvertimeRestDayDuration;
	}
	/**
	 * 计算工作时长中应减去的请假时长
	 * @param currentDayleaveList 当日请假审批列表
	 * @param lastClockTime 打卡开始时间
	 * @param clockTime 打卡结束时间
	 * @return 应减去的请假时长（毫秒数）
	 * @author 王荣
	 */
	public static long calculateLeaveDecreaseDuration(List<Map<String, Object>> currentDayleaveList,String lastClockTime,String clockTime) {
		if(currentDayleaveList==null) {
			return 0;
		}
		long decreaseDuration = 0;
		for(Map<String, Object> currentDayleaveMap : currentDayleaveList) {
			String leaveStartTime = currentDayleaveMap.get("startTime").toString();
			String leaveEndTime = currentDayleaveMap.get("endTime").toString();
			double currentLeaveDuration = Double.valueOf(currentDayleaveMap.get("duration").toString());
			//开始打卡时间-请假开始时间
			double mark1 = TimeAndUnix.compareDate(leaveStartTime,lastClockTime);
			//结束打卡时间-请假结束时间
			double mark2 = TimeAndUnix.compareDate(leaveEndTime,clockTime);
			
			if(mark1>=0 && mark2<=0) {
				//如果请假范围包含打卡时间，减去打卡时间
				decreaseDuration += TimeAndUnix.compareDate(lastClockTime,clockTime);
				break;
			}else if(mark1<=0 && mark2>=0) {
				//如果请假范围在打卡时间范围内，减去请假时长(转换为毫秒)
				decreaseDuration += currentLeaveDuration*60*60*1000;
				break;
			}else if(mark1>=0 && TimeAndUnix.compareDate(lastClockTime,leaveEndTime)>=0) {
				//如果请假时间范围只包含打卡开始时间，减去打卡开始时间~请假结束
				decreaseDuration += TimeAndUnix.compareDate(lastClockTime,leaveEndTime);
				break;
			}else if(mark2<=0 && TimeAndUnix.compareDate(leaveStartTime,clockTime)>=0) {
				//如果请假时间范围只包含打卡结束时间，减去请假开始~打卡结束时间
				decreaseDuration += TimeAndUnix.compareDate(leaveStartTime,clockTime);
				break;
			}
		}
		return decreaseDuration;
	}
	/**
	 * 允许休息时计算应减请假时长
	 * @param currentDayleaveList
	 * @param lastClockTime
	 * @param clockTime
	 * @param restStart
	 * @param restEnd
	 * @author 王荣
	 */
	public static long calculateLeaveDecreaseDuration(List<Map<String, Object>> currentDayleaveList,String lastClockTime,String clockTime,String restStart,String restEnd) {
		if(currentDayleaveList==null) {
			return 0;
		}
		long decreaseDuration = 0;
		for(Map<String, Object> currentDayleaveMap : currentDayleaveList) {
			String leaveStartTime = currentDayleaveMap.get("startTime").toString();
			String leaveEndTime = currentDayleaveMap.get("endTime").toString();
			double currentLeaveDuration = Double.valueOf(currentDayleaveMap.get("duration").toString());
			//开始打卡时间-请假开始时间
			double mark1 = TimeAndUnix.compareDate(leaveStartTime,lastClockTime);
			//结束打卡时间-请假结束时间
			double mark2 = TimeAndUnix.compareDate(leaveEndTime,clockTime);
			
			if(mark1>=0 && mark2<=0) {
				//如果请假范围包含打卡时间，减去打卡时间
				decreaseDuration += TimeAndUnix.compareDate(lastClockTime,clockTime);
				//判断打卡范围与休息范围,求出休息时长，然后应减时长-休息时长
				decreaseDuration -= calculationRestDuration(lastClockTime,clockTime,restStart,restEnd);
				break;
			}else if(mark1<=0 && mark2>=0) {
				//如果请假范围在打卡时间范围内，减去请假时长(转换为毫秒)
				decreaseDuration += currentLeaveDuration*60*60*1000;
				//判断请假范围与休息范围
				decreaseDuration -= calculationRestDuration(leaveStartTime,leaveEndTime,restStart,restEnd);
				break;
			}else if(mark1>=0 && TimeAndUnix.compareDate(lastClockTime,leaveEndTime)>=0) {
				//如果请假时间范围只包含打卡开始时间，减去打卡开始时间~请假结束
				decreaseDuration += TimeAndUnix.compareDate(lastClockTime,leaveEndTime);
				//判断打卡开始时间~请假结束这个范围与休息范围
				decreaseDuration -= calculationRestDuration(lastClockTime,leaveEndTime,restStart,restEnd);
				break;
			}else if(mark2<=0 && TimeAndUnix.compareDate(leaveStartTime,clockTime)>=0) {
				//如果请假时间范围只包含打卡结束时间，减去请假开始~打卡结束时间
				decreaseDuration += TimeAndUnix.compareDate(leaveStartTime,clockTime);
				//判断请假开始~打卡结束范围与休息范围
				decreaseDuration -= calculationRestDuration(leaveStartTime,clockTime,restStart,restEnd);
				break;
			}
		}
		return decreaseDuration;
	}
	public static long calculationRestDuration(String lastClockTime,String clockTime,String restStart,String restEnd) {
		long restMillis = 0;
		double lCheck_rStart = TimeAndUnix.compareDate(lastClockTime,restStart);
		double lCheck_rEnd = TimeAndUnix.compareDate(lastClockTime,restEnd);
		double rStart_check = TimeAndUnix.compareDate(restStart,clockTime);
		double rEnd_check = TimeAndUnix.compareDate(restEnd,clockTime);
		if(lCheck_rStart>0 && rEnd_check>0) {
			//08:00-17:00 12:00-13:00休息
			restMillis += TimeAndUnix.compareDate(restStart,restEnd);
		}else if(lCheck_rStart<=0 && lCheck_rEnd>=0 && rEnd_check>0){
			//12:50-17:10 12:00-13:00休息
			restMillis += TimeAndUnix.compareDate(lastClockTime,restEnd);
		}else if(lCheck_rStart>0 && rStart_check>=0 && rEnd_check<=0){
			//07:50-12:30 12:00-13:00休息
			restMillis += TimeAndUnix.compareDate(restStart,clockTime);
		}else if(lCheck_rStart<=0 && lCheck_rEnd>=0 && rEnd_check<=0) {
			//12:10-12:50
			restMillis += TimeAndUnix.compareDate(lastClockTime,clockTime);
		}
		return restMillis;
	}
	/**
	 * 计算请假时长
	 * @param currentDayleaveList
	 * @param attendanceTime
	 * @param workdate
	 * @throws ParseException
	 * @author 王荣
	 */
	public static long calculateLeaveDuration(List<Map<String, Object>> currentDayleaveList,String attendanceTime,String workdate) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		long leaveDuration = 0;
		List<Map<String, Object>> attendTimeList = new ArrayList<Map<String,Object>>();
		if(attendanceTime == null) return 0;
		String[] attendTime1 = attendanceTime.split(" ");
		for(int i=0;i<attendTime1.length;i++) {
			Map<String, Object> attendTimeMap = new HashMap<String,Object>();
			String[] attendTime2 = attendTime1[i].split("-");
			attendTimeMap.put("start", workdate+" "+attendTime2[0]+":00");
			attendTimeMap.put("end", workdate+" "+attendTime2[1]+":00");
			attendTimeList.add(attendTimeMap);
		}
		try {
			/* 遍历请假单 */
			for(Map<String, Object> leaveMap : currentDayleaveList) {
				String startTime = leaveMap.get("startTime").toString();
				String endTime = leaveMap.get("endTime").toString();
				Double duration = Double.valueOf(leaveMap.get("duration").toString());
				//请假的开始结束时间
				DateTime sTime = new DateTime(sdf.parse(startTime));
				DateTime eTime = new DateTime(sdf.parse(endTime));
				int days = TimeAndUnix.getDateDays(startTime,endTime);
				if(days<=0) {//请假没有跨天
					leaveDuration += duration*60*60*1000;
				}else {//跨天请假，计算今天范围内的请假时长
					for(Map<String, Object> attendTimeMap : attendTimeList) {
						String startStr = attendTimeMap.get("start").toString();
						String endStr = attendTimeMap.get("end").toString();
						DateTime start = new DateTime(sdf.parse(startStr));//排班时间
						DateTime end = new DateTime(sdf.parse(endStr));
						if(eTime.isBefore(start) || eTime.isEqual(start) || sTime.isAfter(end) || sTime.isEqual(end)) {
							continue;
						}
						if( (sTime.isBefore(start) || sTime.isEqual(start)) && (eTime.isBefore(end) || eTime.isEqual(end))) {
							//请假时间07:00-09:00 start~eTime
							leaveDuration += TimeAndUnix.compareDate(startStr, endTime);
						}else if( (sTime.isBefore(start) || sTime.isEqual(start)) && (eTime.isAfter(end) || eTime.isEqual(end))) {
							//请假时间07:00-15:00 start~end
							leaveDuration += TimeAndUnix.compareDate(startStr, endStr);
						}else if( (sTime.isAfter(start) || sTime.isEqual(start)) && (eTime.isBefore(end) || eTime.isEqual(end))) {
							//请假时间09:00-10:00 sTime~eTime
							leaveDuration += TimeAndUnix.compareDate(startTime, endTime);
						}else if( (sTime.isAfter(start) || sTime.isEqual(start)) && (eTime.isAfter(end) || eTime.isEqual(end))) {
							//请假时间09:00~15:00 sTime~end
							leaveDuration += TimeAndUnix.compareDate(startTime, endStr);
						}
					}
				}
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return leaveDuration;
	}
	/**
	 * 允许休息时计算请假时长
	 * @param currentDayleaveList
	 * @param attendanceTime
	 * @param workdate
	 * @param restStart
	 * @param restEnd
	 * @throws ParseException
	 * @author 王荣
	 */
	public static long calculateLeaveDuration(List<Map<String, Object>> currentDayleaveList,String attendanceTime,String workdate,String restStart,String restEnd) throws ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		long leaveDuration = 0;
		List<Map<String, Object>> attendTimeList = new ArrayList<Map<String,Object>>();
		String[] attendTime1 = attendanceTime.split(" ");
		for(int i=0;i<attendTime1.length;i++) {
			Map<String, Object> attendTimeMap = new HashMap<String,Object>();
			String[] attendTime2 = attendTime1[i].split("-");
			attendTimeMap.put("start", workdate+" "+attendTime2[0]+":00");
			attendTimeMap.put("end", workdate+" "+attendTime2[1]+":00");
			attendTimeList.add(attendTimeMap);
		}
		for(Map<String, Object> leaveMap : currentDayleaveList) {
			String startTime = leaveMap.get("startTime").toString();
			String endTime = leaveMap.get("endTime").toString();
			Double duration = Double.valueOf(leaveMap.get("duration").toString());
			DateTime sTime = new DateTime(sdf.parse(startTime));
			DateTime eTime = new DateTime(sdf.parse(endTime));
			int days = TimeAndUnix.getDateDays(startTime,endTime);
			if(days<=0) {//请假没有跨天
				leaveDuration += duration*60*60*1000;
			}else {//跨天请假，计算今天范围内的请假时长
				for(Map<String, Object> attendTimeMap : attendTimeList) {
					String startStr = attendTimeMap.get("start").toString();
					String endStr = attendTimeMap.get("end").toString();
					DateTime start = new DateTime(sdf.parse(startStr));//排班时间
					DateTime end = new DateTime(sdf.parse(endStr));
					if(eTime.isBefore(start) || eTime.isEqual(start) || sTime.isAfter(end) || sTime.isEqual(end)) {
						continue;
					}
					if( (sTime.isBefore(start) || sTime.isEqual(start)) && (eTime.isBefore(end) || eTime.isEqual(end))) {
						//请假时间07:00-09:00 start~eTime
						leaveDuration += TimeAndUnix.compareDate(startStr, endTime);
						leaveDuration -= calculationRestDuration(startStr, endTime,restStart,restEnd);
					}else if( (sTime.isBefore(start) || sTime.isEqual(start)) && (eTime.isAfter(end) || eTime.isEqual(end))) {
						//请假时间07:00-15:00 start~end
						leaveDuration += TimeAndUnix.compareDate(startStr, endStr);
						leaveDuration -= calculationRestDuration(startStr, endStr,restStart,restEnd);
					}else if( (sTime.isAfter(start) || sTime.isEqual(start)) && (eTime.isBefore(end) || eTime.isEqual(end))) {
						//请假时间09:00-10:00 sTime~eTime
						leaveDuration += TimeAndUnix.compareDate(startTime, endTime);
						leaveDuration -= calculationRestDuration(startTime, endTime,restStart,restEnd);
					}else if( (sTime.isAfter(start) || sTime.isEqual(start)) && (eTime.isAfter(end) || eTime.isEqual(end))) {
						//请假时间09:00~15:00 sTime~end
						leaveDuration += TimeAndUnix.compareDate(startTime, endStr);
						leaveDuration -= calculationRestDuration(startTime, endStr,restStart,restEnd);
					}
				}
			}
		}
		return leaveDuration;
	}
}
